﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using SP = Microsoft.SharePoint.Client;

namespace com.sharepointutils.application.Forms
{
    public partial class UploadForm : Form
    {

        private List<String> selections = new List<string>();
        private List<Exception> backgroundWorkerErrorList = new List<Exception>();

        public UploadForm(SharePointConnection connection, Form parent)
        {
            InitializeComponent();

            combo_prop.Items.Add(new KeyValuePair<String, String>("File Name", "File Name"));

            this.MdiParent = parent;
            this.Text = "Upload - " + connection.List;
            this.Connection = connection;
            lbl_upload_current.Text = connection.Label;
            this.Tag = connection.Label;
            load();

            Icon iconForFolder = com.sharepointutils.application.Properties.Resources.Folder;
            imageList.Images.Add("folder", iconForFolder);
        }

        public void ReportError(Exception ex)
        {
            ((MainForm)this.MdiParent).ReportError(ex);
        }

        Boolean DropDownFilled = false;
        SharePointConnection Connection;
        Dictionary<String, object> properties = new Dictionary<string, object>();
        List<ListViewItem> currentCollection;
        String currentContentTypes;


        private void load()
        {
            lsbox_contentTypes.DataSource = null;
            if (Connection != null && !String.IsNullOrEmpty(Connection.List))
            {
                lsbox_contentTypes.DataSource = SharePointUtilities.getContentTypes(Connection.URL, Connection.List, Connection.Credentials);
            }
        }

        private void btn_delete_Click(object sender, EventArgs e)
        {
            foreach (int i in lstbox_props.CheckedIndices)
            {
                KeyValuePair<string, string> item = (KeyValuePair<String, String>)lstbox_props.Items[i];
                properties.Remove(item.Key);
                lstbox_props.Items.RemoveAt(i);
            }
        }

        private void btn_addProp_Click(object sender, EventArgs e)
        {
            try
            {
                if (!String.IsNullOrEmpty(combo_prop.Text) && lsbox_fields.SelectedIndex >= 0)
                {
                    var item = (KeyValuePair<String, String>)lsbox_fields.SelectedItem;
                    //lsbox_fields.Items.RemoveAt(lsbox_fields.SelectedIndex);

                    KeyValuePair<String, String> temp = new KeyValuePair<string, string>(item.Value, item.Key + " - " + combo_prop.Text);

                    if (combo_prop.SelectedItem == null)
                    {
                        properties.Add(item.Value, combo_prop.SelectedText);
                    }
                    else
                    {
                        properties.Add(item.Value, ((KeyValuePair<String, String>)combo_prop.SelectedItem).Value);
                    }
                    //String temp = item.Key + " - " + txt_prop.Text;
                    lstbox_props.Items.Add(temp);
                    combo_prop.Text = String.Empty;
                }
            }
            finally
            { }
        }

        private void btn_open_Click(object sender, EventArgs e)
        {
            if (folderBrowser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                String[] files = Directory.GetFiles(folderBrowser.SelectedPath);
                loadFilesToList(files, ref list_files);
                String[] folders = Directory.GetDirectories(folderBrowser.SelectedPath);
                loadFilesToList(folders, ref list_files);
            }
        }

        private void loadFilesToList(String[] files, ref ListView lv)
        {
            foreach (var f in files)
            {
                if ((File.GetAttributes(f) & FileAttributes.Directory) != FileAttributes.Directory)
                {
                    Icon iconForFile = SystemIcons.WinLogo;
                    FileInfo file = new FileInfo(f);
                    ListViewItem item = new ListViewItem(file.Name, 1);
                    iconForFile = Icon.ExtractAssociatedIcon(file.FullName);

                    if (!imageList.Images.ContainsKey(file.Extension))
                    {
                        // If not, add the image to the image list.
                        iconForFile = System.Drawing.Icon.ExtractAssociatedIcon(file.FullName);
                        imageList.Images.Add(file.Extension, iconForFile);
                    }
                    item.ImageKey = file.Extension;
                    item.Tag = f;
                    lv.Items.Add(item);
                }
                else
                {
                    DirectoryInfo folder = new DirectoryInfo(f);

                    if (!DropDownFilled)
                    {
                        BuildFolderLevels(folder, 1);
                        DropDownFilled = true;
                    }

                    ListViewItem item = new ListViewItem(folder.Name);
                    item.ImageKey = "folder";
                    item.Tag = folder.FullName;
                    lv.Items.Add(item);
                }
            }
            lv.Update();
        }

        private void BuildFolderLevels(DirectoryInfo folder, int level)
        {
            combo_prop.Items.Add(new KeyValuePair<String, String>("Folder Level " + level + " (" + folder.Name + ")", "Folder Level " + level));
            DirectoryInfo[] subfolders = folder.GetDirectories();
            if (subfolders.Length != 0)
            {
                BuildFolderLevels(subfolders[0], level + 1);
            }
        }

        private void list_files_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.All;
        }

        private void list_files_DragDrop(object sender, DragEventArgs e)
        {
            String[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            loadFilesToList(files, ref list_files);
        }

        private void btn_save_Click(object sender, EventArgs e)
        {
            currentCollection = new List<ListViewItem>();
            selections = new List<string>();

            if (!String.IsNullOrWhiteSpace(comboBox_folderOptions.Text))
                selections.Add(comboBox_folderOptions.Text);

            foreach (ListViewItem i in list_files.Items)
            {
                currentCollection.Add(i);
            }
            lbl_status.Text = "Uploading...";
            progbar_status.Value = 0;
            currentContentTypes = lsbox_contentTypes.SelectedItem.ToString();
            backgroundWorker.RunWorkerAsync(); 
        }


        private void UploadFileAsDocumentSet(DirectoryInfo folder, Dictionary<String, object> uploadProperties)
        {
            UploadFileAsDocumentSet(folder, 1, uploadProperties);
        }

        private void UploadFileAsDocumentSet(DirectoryInfo folder, int level, Dictionary<String, object> uploadProperties)
        {
            Dictionary<String, object> copy = new Dictionary<string, object>(uploadProperties);
                var folderProperties = from f in uploadProperties
                        where f.Value.ToString() == "Folder Level " + level
                        select f.Key;

                var fileProperties = from f in uploadProperties
                                       where f.Value.ToString() == "File Name"
                                       select f.Key;

                foreach (String key in folderProperties)
                {
                    copy[key] = folder.Name;
                }

                foreach (DirectoryInfo f in folder.GetDirectories())
                {
                    UploadFileAsDocumentSet(f, level + 1, copy);
                }

            foreach (FileInfo file in folder.GetFiles())
            {
                try
                {
                    foreach (String key in fileProperties)
                    {
                        copy[key] = Path.GetFileNameWithoutExtension(file.Name).MakeSafe();
                    }

                    String url = SharePointUtilities.createDocumentSet(Connection.URL, Connection.List, Connection.Credentials, currentContentTypes, Path.GetFileNameWithoutExtension(file.Name).MakeSafe(), textBox_rootFolder.Text, copy);
                    if (!String.IsNullOrEmpty(url))
                    {
                        saveFile(file.FullName, url);
                    }
                    else
                    {
                        throw new Exception("Cannot create Document Set and did not upload the following file " + file.FullName );
                    }
                }
                catch (Exception ex)
                {
                    backgroundWorkerErrorList.Add(ex);
                    //ReportError(ex);
                }
            }    
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            double total = currentCollection.Count;
            double current = 0;
            foreach (ListViewItem file in currentCollection)
            {
                try
                {
                    if ((File.GetAttributes(file.Tag.ToString()) & FileAttributes.Directory) != FileAttributes.Directory)
                    {
                        FileStream fs = File.OpenRead(file.Tag.ToString());
                        //byte[] bytes = new byte[fs.Length];
                        //fs.Read(bytes, 0, (int)fs.Length);

                        Dictionary<String, Object> tempProperties = new Dictionary<string, object>();

                        foreach (var prop in properties)
                        {
                            if (prop.Value.ToString() == "File Name")
                            {
                                tempProperties[prop.Key] = Path.GetFileNameWithoutExtension(file.Text);
                            }
                            else
                            {
                                tempProperties[prop.Key] = prop.Value;
                            }
                        }

                        
                        if (selections.Contains("Save File as Document Set"))
                        {
                            String docSeturl = SharePointUtilities.createDocumentSet(Connection.URL, Connection.List, Connection.Credentials, currentContentTypes, Path.GetFileNameWithoutExtension(file.Text).MakeSafe(), textBox_rootFolder.Text, tempProperties);
                            SharePointUtilities.uploadDocument(Connection.URL, docSeturl, Connection.Credentials, file.Text.MakeSafe(), fs);
                        }
                        else
                        {
                            SharePointUtilities.uploadDocument(Connection.URL, Connection.Credentials, Connection.List, file.Text.MakeSafe(), fs, tempProperties);
                        }
                        fs.Dispose();
                    }
                    else
                    {
                        DirectoryInfo folder = new DirectoryInfo(file.Tag.ToString());
                        UploadFileAsDocumentSet(folder, properties);
                    }
                }
                catch (Exception ex)
                {
                    backgroundWorkerErrorList.Add(ex);
                    //ReportError(ex);
                    //this.ErrorLog.Append("Could not upload - " + file.Tag + Environment.NewLine + " " + ex.Message);
                }
                current++;
                backgroundWorker.ReportProgress((int)((current / total) * 100));
            }
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            list_files.Items.Clear();
            lbl_status.Text = "Done...";
            progbar_status.Value = 100;

            foreach (var exception in backgroundWorkerErrorList)
            {
                ReportError(exception);
            }
            backgroundWorkerErrorList.Clear();
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progbar_status.Value = e.ProgressPercentage;
        }


        private void saveFile(String file, String folderURL)
        {
            try
            {
                String filename = Path.GetFileName(file);
                FileStream fs = File.OpenRead(file);
                SharePointUtilities.uploadDocument(Connection.URL, folderURL, Connection.Credentials, filename.MakeSafe(), fs);
            }
            catch (Exception ex)
            {
                backgroundWorkerErrorList.Add(ex);
            }
        }

        private void saveFiles(String path)
        {
            foreach (var file in Directory.GetFiles(path))
            {
                try
                {
                    String filename = Path.GetFileName(file);
                    FileStream fs = File.OpenRead(file);
                    SharePointUtilities.uploadDocument(Connection.URL, Connection.Credentials, Connection.List, filename.MakeSafe(), fs);
                }
                catch (Exception ex)
                {
                    backgroundWorkerErrorList.Add(ex);
                    //ReportError(ex);
                    //this.ErrorLog.Append("Could not upload - " + file + Environment.NewLine + " " + ex.Message);
                }
            }
            foreach (var folder in Directory.GetDirectories(path))
            {
                saveFiles(folder);
            }
        }

        private void saveFiles(String path, Dictionary<String, object> properties)
        {
            foreach (var file in Directory.GetFiles(path))
            {
                try
                {
                    String filename = Path.GetFileName(file);
                    FileStream fs = File.OpenRead(file);
                    SharePointUtilities.uploadDocument(Connection.URL, Connection.Credentials, Connection.List, filename.MakeSafe(), fs, properties);
                }
                catch (Exception ex)
                {
                    backgroundWorkerErrorList.Add(ex);
                    //ReportError(ex);
                    //this.ErrorLog.Append("Could not upload - " + file + Environment.NewLine + " " + ex.Message);
                }
            }
            foreach (var folder in Directory.GetDirectories(path))
            {
                saveFiles(folder, properties);
            }
        }

        private void lsbox_contentTypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            lsbox_fields.Items.Clear();
            properties = new Dictionary<string, object>();
            try
            {
                using (SP.ClientContext ctx = new SP.ClientContext(Connection.URL))
                {
                    ctx.Credentials = Connection.Credentials;
                    SP.List list = ctx.Web.Lists.GetByTitle(Connection.List);
                    SP.ContentTypeCollection listContentTypes = list.ContentTypes;
                    String ctName = lsbox_contentTypes.SelectedItem.ToString();
                    var result = ctx.LoadQuery(listContentTypes.Where(c => c.Name == ctName));
                    ctx.ExecuteQuery();
                    SP.ContentType targetContentType = result.FirstOrDefault();
                    ctx.Load(targetContentType.Fields);
                    ctx.ExecuteQuery();

                    foreach (SP.Field field in targetContentType.Fields)
                    {
                        lsbox_fields.Items.Add(new KeyValuePair<String, String>(field.Title, field.InternalName));
                    }
                }
            }
            catch
            {
                lsbox_fields.Items.Add("Failed to load fields");
            }
        }

    }
}
